#include "socks5app.h"
#include <iostream>
#include "json/json.h"
#include <string.h>
#include "auth_type.h"
#include "socks5_thread.h"

using std::cerr;
using std::cout;
using std::endl;


/**
 * @brief CSocks5App::load_config
 * The configure file is /etc/ssrv/ssrv.config.
 * {
 * "auth_type":"none", #"none" or "password"
 * "user_name":"user_name_abc", #user name
 * "password":"somelongpassword", #password
 * "IP_white_list":["218.85.152.99", "218.85.157.99"]
 * }
 */
#include "util/File.h"

CSocks5App::CSocks5App(){

}

CSocks5App::~CSocks5App(){;}

void CSocks5App::socket_accepted(int fd_accept){
    std::shared_ptr<CSocks5Thread> x(new CSocks5Thread(fd_accept));
    allThreads_.push_back(x);
}

void CSocks5App::stop(){
    for (auto i : allThreads_){
        if (!i->get_is_thread_end())
            i->stop();
    }
    check();
}

void CSocks5App::check(){
    for (SOCKSThreadIter it = allThreads_.begin(); it != allThreads_.end(); ){
        if ((*it)->get_is_thread_end())
        {
            (*it)->join();
            it = allThreads_.erase(it);
            cout << "remove a thread worker object." << endl;
        }
        else
            ++it;
    }
}

extern std::string g_config_file;

bool CSocks5App::load_config()
{
    std::string config_file = g_config_file;
    if (!qcutil::File::exists(config_file))
    {
        cerr << "The configure file does not exist." << endl;
        return false;
    }

    qcutil::FileReader fr(config_file);
    if (!fr.open()){
        return false;
    }
    std::string content = fr.read();
    fr.close();
    if (content.empty()){
        cerr << "Empty configure file or read file error!" << endl;
        return false;
    }

    Json::Reader jr;
    Json::Value jv;

    if (!jr.parse(content, jv))
    {
        cerr << "parse configure failed." << endl;
    }

    try {
        std::string at = jv["auth_type"].asString(); //"none" or "password"
        if (at == "none")
        {
            CAuthType::getInstance().setAuthorizationMode(EAM_None);
        }
        else if("password" == at)
        {
            CAuthType::getInstance().setAuthorizationMode(EAM_Password);
            CAuthType::getInstance().setUserName(jv["user_name"].asString());
            CAuthType::getInstance().setPassword(jv["password"].asString());
        }
        else
        {
            cerr << "Authorizatio: Neither None or Password was set." << endl;
            return false;
        }
    }
    catch(Json::Exception& e)
    {
        cerr << e.what() << endl;
        CAuthType::getInstance().setAuthorizationMode(EAM_Unknown);
        return false;
    }

    return true;
}

std::string CAuthType::getUserName() const
{
    return user_name_;
}

void CAuthType::setUserName(const std::string &user_name)
{
    user_name_ = user_name;
}

AuthorizationMode CAuthType::getAuthorizationMode() const
{
    return am_;
}

void CAuthType::setAuthorizationMode(const AuthorizationMode &am)
{
    am_ = am;
}

std::string CAuthType::getPassword() const
{
    return password_;
}

void CAuthType::setPassword(const std::string &password)
{
    password_ = password;
}
